package tests;
import items.Battery;
import items.RepairKit;


import exceptions.IllegalPlacementException;
import exceptions.IllegalTerminatedException;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import roborally.Board;
import roborally.Direction;
import roborally.EnergyAmount;
import roborally.EnergyUnit;
import roborally.Orientation;
import roborally.Position;

import elements.Robot;
import elements.Wall;
import gui.Facade;

/**
 * @version	3.0
 * @author 	Lies Tambeur 	r0264469	2Bcwsbbh
 * @author	Eline Vanrykel	r0264543	2Bcwselt
 * 
 */
public class RobotTest {
	
	private Robot robotOrient0Energy15000;
	private Robot robotOrient0Energy0;
	private Robot robotOrient2Energy50;
	private Robot robotOrient3Energy8000;
	private Facade facade;
	private EnergyAmount zeroEnergy;
	private EnergyAmount thousandEnergy;

	/**
	 * Set up a mutable test fixture.
	 * 
	 * @post   The variable robot33Orient0Energy20000 references a new
	 *         robot with with position (3,3), energy 20000 and orientation 0.
	 * @post   The variable robot82Orient3Energy8000 references a new
	 *         robot with  position (8,2), energy 8000 and orientation 3.
	 */
	@Before
	public void setUp() throws Exception {
		zeroEnergy = new EnergyAmount();
		thousandEnergy = new EnergyAmount(1000,EnergyUnit.WATTSECONDS);
		robotOrient0Energy15000 = new Robot(Orientation.UP, thousandEnergy.multiplyAndReturn(15));
		robotOrient3Energy8000 = new Robot(Orientation.LEFT, thousandEnergy.multiplyAndReturn(8));
		robotOrient2Energy50 = new Robot(Orientation.DOWN, new EnergyAmount(50,EnergyUnit.WATTSECONDS));
		robotOrient0Energy0 = new Robot(Orientation.UP, zeroEnergy);
		facade=new Facade();
	}
	
	@Test
	public final void getItemsSorted(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(0.5));
		Battery battery1  = new Battery(thousandEnergy, 200);
		Battery battery2 = new Battery(thousandEnergy,500);
		Battery battery3 = new Battery(thousandEnergy, 1);
		board9.putElement(new Position(0,0), robot);
		board9.putElement(new Position(0,0), battery1);
		board9.putElement(new Position(0,0), battery2);
		board9.putElement(new Position(0,0), battery3);
		robot.pickUp(battery1);
		robot.pickUp(battery2);
		robot.pickUp(battery3);
		assertEquals(3, robot.getNbOfItems());
		assertEquals(battery2, robot.getIthHeaviestItem(0));
		assertEquals(battery1, robot.getIthHeaviestItem(1));
		assertEquals(battery3, robot.getIthHeaviestItem(2));
		board9.terminate();
	}
		
	@Test 
	public final void turn(){
		Robot robot = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(2.2));
		robot.turn(Direction.CLOCKWISE);
		assertEquals(Orientation.RIGHT, robot.getOrientation());
		assertEquals(thousandEnergy.multiplyAndReturn(2.2).subtractAndReturn(Robot.getEnergyForTurn()), robot.getEnergy());
	}
	
	@Test 
	public final void turnCounter(){
		Robot robot = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(2.2));
		robot.turn(Direction.COUNTERCLOCKWISE);
		assertEquals(Orientation.LEFT, robot.getOrientation());
		assertEquals(thousandEnergy.multiplyAndReturn(2.2).subtractAndReturn(Robot.getEnergyForTurn()), robot.getEnergy());
	}
	
	//move tests
	
	@Test
	public final void move_LegalCase(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		Robot robot = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(2.2));
		board9.putElement(new Position(6, 1), robot);
		robot.move();
		assertEquals(new Position(6,0), robot.getPosition());
		assertEquals(thousandEnergy.multiplyAndReturn(2.2).subtractAndReturn(robot.getEnergyForMove()), robot.getEnergy());
		board9.terminate();
	}
	
	@Test
	public final void move_InsufficientEnergy(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		board9.putElement(new Position(5,5), robotOrient0Energy0);
		try{
			robotOrient0Energy0.move();
		}
		catch(AssertionError e){
			assertTrue(true);
		}
		board9.terminate();
	}
	
	@Test
	public final void move_GoOutOfBoard(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		board9.putElement(new Position(6, 0), robotOrient0Energy15000);
		try{
			robotOrient0Energy15000.move();
		}
		catch(IllegalPlacementException e){
			assertTrue(true);
		}
		assertEquals(thousandEnergy.multiplyAndReturn(15),robotOrient0Energy15000.getEnergy());
		board9.terminate();
	}
	
	@Test
	public final void move_TerminatedRobot(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		board9.putElement(new Position(5, 0), robotOrient0Energy15000);
		robotOrient0Energy15000.terminate();
		try{
			robotOrient0Energy15000.move();
		}
		catch(IllegalTerminatedException e){
			assertTrue(true);
		}
		assertEquals(thousandEnergy.multiplyAndReturn(15),robotOrient0Energy15000.getEnergy());
		board9.terminate();
	}
	
	@Test
	public final void move_RobotNotOnBoard(){
		try{
			robotOrient0Energy15000.move();
		}
		catch(IllegalStateException e){
			assertTrue(true);
		}
		assertEquals(thousandEnergy.multiplyAndReturn(15),robotOrient0Energy15000.getEnergy());
	}
	
	//minEnergyToReach tests
	
	@Test
	public final void minEnergyToReach_LegalCase(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		Robot robot = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(10));
		board9.putElement(new Position(6, 1), robot);
		assertEquals((Robot.getEnergyForTurn().multiplyAndReturn(2).addAndReturn(robot.getEnergyForMove())).toEnergyUnit(EnergyUnit.WATTSECONDS).getAmount(), robot.minEnergyToReachInWattSeconds(new Position(6,2)),0.0);
		board9.terminate();
	}
	
	@Test
	public final void minEnergyToReach_CaseNotReachablePositionIllegalGoToPosition(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		Robot robot = new Robot(Orientation.UP,thousandEnergy);
		board9.putElement(new Position(3,3), robot);
		board9.putElement(new Position(5,5), new Wall());
		assertEquals(-1, robot.minEnergyToReachInWattSeconds(new Position(5,5)),0);
		board9.terminate();
	}
	
	@Test
	public final void minEnergyToReach_NotOnBoard(){
		Robot robot = new Robot(Orientation.UP,zeroEnergy);
		assertEquals(-1, robot.minEnergyToReachInWattSeconds(new Position(10,10)),0);
	}
	
	
	//move tests
	
	@Test
	public final void moveNextTo_twoOneMoves(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot1 = new Robot(Orientation.DOWN,thousandEnergy.multiplyAndReturn(5));
		Robot robot2 = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(5));
		
		board9.putElement(new Position(0,4), robot1);
		board9.putElement(new Position(5,4), robot2);
	
		
		robot2.moveNextTo(robot1);
		
		assertEquals(new Position(4,4), robot1.getPosition());
		assertEquals(new Position(5,4), robot2.getPosition());
		
		assertEquals(thousandEnergy.multiplyAndReturn(2.9),robot1.getEnergy());
		assertEquals(thousandEnergy.multiplyAndReturn(5),robot2.getEnergy());
		board9.terminate();
	}
	@Test
	public final void moveNextTo_twoWallsBothMoveReversed(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot1 = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(0.5));
		Robot robot2 = new Robot(Orientation.LEFT,thousandEnergy.multiplyAndReturn(5.3));
		
		board9.putElement(new Position(0,3), robot1);
		board9.putElement(new Position(3,4), robot2);
		
		board9.putElement(new Position(5,1), new Wall());
		board9.putElement(new Position(4,1), new Wall());
		board9.putElement(new Position(3,1), new Wall());
		board9.putElement(new Position(2,2), new Wall());
		board9.putElement(new Position(3,3), new Wall());
		board9.putElement(new Position(2,4), new Wall());
		board9.putElement(new Position(2,6), new Wall());
		board9.putElement(new Position(3,5), new Wall());
		board9.putElement(new Position(3,7), new Wall());
		board9.putElement(new Position(4,7), new Wall());
		board9.putElement(new Position(5,7), new Wall());
		
		
		robot2.moveNextTo(robot1);
		
		assertEquals(new Position(0,2), robot1.getPosition());
		assertEquals(new Position(3,2), robot2.getPosition());
		
		assertEquals(zeroEnergy,robot1.getEnergy());
		assertEquals(thousandEnergy.multiplyAndReturn(2.9),robot2.getEnergy());
		board9.terminate();
	}
	
	@Test
	public final void moveNextTo_twoWallsBothMove(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot1 = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(0.5));
		Robot robot2 = new Robot(Orientation.LEFT,thousandEnergy.multiplyAndReturn(5.3));
		
		board9.putElement(new Position(0,3), robot1);
		board9.putElement(new Position(3,4), robot2);
		
		board9.putElement(new Position(5,1), new Wall());
		board9.putElement(new Position(4,1), new Wall());
		board9.putElement(new Position(3,1), new Wall());
		board9.putElement(new Position(2,2), new Wall());
		board9.putElement(new Position(3,3), new Wall());
		board9.putElement(new Position(2,4), new Wall());
		board9.putElement(new Position(2,6), new Wall());
		board9.putElement(new Position(3,5), new Wall());
		board9.putElement(new Position(3,7), new Wall());
		board9.putElement(new Position(4,7), new Wall());
		board9.putElement(new Position(5,7), new Wall());
		
		
		robot1.moveNextTo(robot2);
		
		assertEquals(new Position(0,2), robot1.getPosition());
		assertEquals(new Position(3,2), robot2.getPosition());
		
		assertEquals(zeroEnergy,robot1.getEnergy());
		assertEquals(thousandEnergy.multiplyAndReturn(2.9),robot2.getEnergy());
		
		board9.terminate();
	}
	
	
	@Test
	public final void moveNextTo_twoWallsNoMoves(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot1 = new Robot(Orientation.UP,zeroEnergy);
		Robot robot2 = new Robot(Orientation.LEFT,thousandEnergy.multiplyAndReturn(5.3));
		
		board9.putElement(new Position(0,3), robot1);
		board9.putElement(new Position(3,4), robot2);
		
		board9.putElement(new Position(5,1), new Wall());
		board9.putElement(new Position(4,1), new Wall());
		board9.putElement(new Position(3,1), new Wall());
		board9.putElement(new Position(2,2), new Wall());
		board9.putElement(new Position(3,3), new Wall());
		board9.putElement(new Position(2,4), new Wall());
		board9.putElement(new Position(2,6), new Wall());
		board9.putElement(new Position(3,5), new Wall());
		board9.putElement(new Position(3,7), new Wall());
		board9.putElement(new Position(4,7), new Wall());
		board9.putElement(new Position(5,7), new Wall());
		
		
		robot1.moveNextTo(robot2);
		
		assertEquals(new Position(0,3), robot1.getPosition());
		assertEquals(new Position(3,4), robot2.getPosition());
		
		assertEquals(zeroEnergy,robot1.getEnergy());
		assertEquals(thousandEnergy.multiplyAndReturn(5.3),robot2.getEnergy());
		board9.terminate();
	}
	
	@Test
	public final void moveNextTo_twoWalls(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot1 = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(0.5));
		Robot robot2 = new Robot(Orientation.LEFT,thousandEnergy.multiplyAndReturn(4));
		
		board9.putElement(new Position(0,2), robot1);
		board9.putElement(new Position(7,0), robot2);
		
		board9.putElement(new Position(1,1), new Wall());
		board9.putElement(new Position(2,1), new Wall());
		board9.putElement(new Position(3,1), new Wall());
		board9.putElement(new Position(4,1), new Wall());
		board9.putElement(new Position(5,1), new Wall());
		
		robot1.moveNextTo(robot2);
		
		assertEquals(new Position(0,1), robot1.getPosition());
		assertEquals(new Position(0,0), robot2.getPosition());
		
		assertEquals(zeroEnergy,robot1.getEnergy());
		assertEquals(thousandEnergy.multiplyAndReturn(0.5),robot2.getEnergy());
		board9.terminate();
	}
	
	@Test
	public final void moveNextTo_oneWallsInsufficientEnergy(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		board9.putElement(new Position(1,1), robotOrient0Energy0);
		Robot robot = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(2.2));
		board9.putElement(new Position(6, 1), robot);
		board9.putElement(new Position(3,0), new Wall());
		board9.putElement(new Position(3,1), new Wall());
		board9.putElement(new Position(3,2), new Wall());
		board9.putElement(new Position(3,3), new Wall());
		board9.putElement(new Position(3,4), new Wall());
		robot.moveNextTo(robotOrient0Energy0);
		assertEquals(new Position(4,1), robot.getPosition());
		assertEquals(robot.getEnergyForMove().multiplyAndReturn(2).addAndReturn(Robot.getEnergyForTurn()), robot.getEnergy());
		board9.terminate();
	}
	
	@Test
	public final void moveNextTo_oneWall(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		board9.putElement(new Position(1,1), robotOrient0Energy0);
		Robot robot = new Robot(Orientation.UP,thousandEnergy.multiplyAndReturn(15));
		board9.putElement(new Position(6, 1), robot);
		board9.putElement(new Position(3,0), new Wall());
		board9.putElement(new Position(3,1), new Wall());
		board9.putElement(new Position(3,2), new Wall());
		board9.putElement(new Position(3,3), new Wall());
		board9.putElement(new Position(3,4), new Wall());
		robot.moveNextTo(robotOrient0Energy0);
		assertEquals(new Position(2,1), robot.getPosition()); // of 1 2
		assertEquals(thousandEnergy.multiplyAndReturn(15).subtractAndReturn(robot.getEnergyForMove().multiplyAndReturn(12)).subtractAndReturn(Robot.getEnergyForTurn().multiplyAndReturn(4)), robot.getEnergy());
		board9.terminate();
	}
	
	@Test
	public final void moveNextTo_oneInsufficientEnergy(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		board9.putElement(new Position(1,1), robotOrient0Energy0);
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(1.7));
		board9.putElement(new Position(5, 2), robot);
		robot.moveNextTo(robotOrient0Energy0);
		assertEquals(zeroEnergy, robot.getEnergy());
		assertEquals(new Position(2,2), robot.getPosition());
		board9.terminate();
	}	
	
	@Test
	public final void shoot_OneWall(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.UP,Robot.getEnergyRequiredToShoot());
		board9.putElement(new Position(3, 1), robot);
		board9.putElement(new Position(3,0), new Wall());
		robot.shoot();
		assertEquals(zeroEnergy, robot.getEnergy());
		assertTrue(!board9.<Wall>getElementsOfType(Wall.class).isEmpty());
		board9.terminate();
	}
	
	@Test
	public final void shoot_NoObject(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.UP,Robot.getEnergyRequiredToShoot());
		board9.putElement(new Position(0,1), robot);
		robot.shoot();
		assertEquals(zeroEnergy, robot.getEnergy());
		assertEquals(1, board9.getAllElements().size());
		board9.terminate();
	}
	
	@Test
	public final void shoot_NotOnBoard(){
		Robot robot = new Robot(Orientation.UP,Robot.getEnergyRequiredToShoot());
		assertNull(robot.getBoard());
		try{
			robot.shoot();
		}
		catch (IllegalStateException e) {
			assertTrue(true);
			assertEquals(Robot.getEnergyRequiredToShoot(), robot.getEnergy()); 
		}
	}
	
	@Test
	public final void shoot_RobotTerminated(){
		Board board8 = new Board(8,8);
		facade.addBoard(board8);
		
		Robot robot = new Robot(Orientation.UP,Robot.getEnergyRequiredToShoot());
		board8.putElement(new Position(0,1), robot);
		board8.putElement(new Position(0,0), new Wall());
		robot.terminate();
		try{
			robot.shoot();
		}
		catch (IllegalTerminatedException e) {
			assertTrue(true);
			assertEquals(Robot.getEnergyRequiredToShoot(), robot.getEnergy());
			assertEquals(board8.getAllElements().size(), 1);
		}
		board8.terminate();
	}
	
	@Test
	public final void smallConstror_Legal(){
		Robot robot = new Robot();
		assertEquals(thousandEnergy.multiplyAndReturn(15), robot.getEnergy());
		assertEquals(Orientation.RIGHT, robot.getOrientation());
	}
	
	@Test
	public final void Constror_Illegal(){
		Robot robot = new Robot(Orientation.UP,new EnergyAmount(1234567890,EnergyUnit.WATTSECONDS));
		assertEquals(robot.getMaxEnergy(), robot.getEnergy());
		assertEquals(Orientation.UP, robot.getOrientation());
	}
	
	@Test
	public final void getRelativeEnergy(){
		assertEquals(robotOrient3Energy8000.getRelativeEnergy(), new EnergyAmount(robotOrient3Energy8000.getEnergy().toEnergyUnit(EnergyUnit.WATTSECONDS).getAmount() / robotOrient3Energy8000.getMaxEnergy().toEnergyUnit(EnergyUnit.WATTSECONDS).getAmount(),EnergyUnit.WATTSECONDS));
	}
	
	//recharge tests
	
	@Test
	public final void recharge_Normal(){
		robotOrient2Energy50.recharge(thousandEnergy.multiplyAndReturn(0.05));
		assertEquals(thousandEnergy.multiplyAndReturn(0.1), robotOrient2Energy50.getEnergy());
	}
	
	@Test
	public final void recharge_OverMax(){
		try{
			robotOrient0Energy15000.recharge(thousandEnergy.multiplyAndReturn(0.2));
		}
		catch(AssertionError e){
			assertEquals(1, 1);
		}
		assertEquals(robotOrient0Energy15000.getMaxEnergy(),robotOrient0Energy15000.getEnergy());
	}
	
	//pickup tests
	
	@Test
	public final void pickUp_LegalCase(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(0.5));
		Battery battery  = new Battery(thousandEnergy, 200);
		board9.putElement(new Position(0,0), robot);
		board9.putElement(new Position(0,0), battery);
		robot.pickUp(battery);
		assertEquals(1, robot.getNbOfItems());
		assertEquals(200,robot.getLoad());
		assertTrue(robot.getItems().contains(battery));
		board9.terminate();
	}
	
	@Test
	public final void pickUp_LegalCaseMultipleItems(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(0.5));
		Battery battery1  = new Battery(thousandEnergy, 200);
		Battery battery2 = new Battery(thousandEnergy,500);
		board9.putElement(new Position(0,0), robot);
		board9.putElement(new Position(0,0), battery1);
		board9.putElement(new Position(0,0), battery2);
		robot.pickUp(battery1);
		robot.pickUp(battery2);
		assertEquals(2, robot.getNbOfItems());
		assertEquals(700,robot.getLoad());
		assertTrue(robot.getItems().contains(battery1));
		assertTrue(robot.getItems().contains(battery2));
		board9.terminate();
	}
	
	@Test
	public final void pickUp_RobotAndBatteryNotSamePosition(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(0.5));
		Battery battery  = new Battery(thousandEnergy, 200);
		board9.putElement(new Position(0,1), robot);
		board9.putElement(new Position(0,0), battery);
		try{
			robot.pickUp(battery);
		}
		catch (IllegalStateException e) {
			assertTrue(true);
		}
		board9.terminate();
	}
	
	@Test
	public final void pickUp_TerminatedItem(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(0.5));
		Battery battery  = new Battery(thousandEnergy, 200);
		board9.putElement(new Position(8,8), robot);
		board9.putElement(new Position(8,8), battery);
		battery.terminate();
		try{
			robot.pickUp(battery);
		}
		catch(IllegalTerminatedException e){
			assertTrue(true);
			assertEquals(0, robot.getNbOfItems());
			assertEquals(0,robot.getLoad());
			assertFalse(robot.getItems().contains(battery));
		}
		board9.terminate();
	}
	
	@Test
	public final void pickUp_ItemAlreadyInPossession(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(0.5));
		Battery battery  = new Battery(thousandEnergy, 200);
		board9.putElement(new Position(8,8), robot);
		board9.putElement(new Position(8,8), battery);
		robot.pickUp(battery);
		try{
			robot.pickUp(battery);
		} catch(IllegalStateException e){
			assertTrue(true);
		}
		board9.terminate();
	}
	
	//terminate tests
	
	@Test
	public final void terminate_NoItemsInPossesssion(){
		Board board7 = new Board(7,7);
		facade.addBoard(board7);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(0.5));
		board7.putElement(new Position(6,6), robot);
		robot.terminate();
		assertTrue(robot.isTerminated());
		assertNull(robot.getBoard());
		board7.terminate();
	}
	
	@Test
	public final void terminate_RobotOnBoardMultipleItemsInPossesssion(){
		Board board7 = new Board(7,7);
		facade.addBoard(board7);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(0.5));
		Battery battery1  = new Battery(thousandEnergy, 200);
		Battery battery2 = new Battery(thousandEnergy,500);
		board7.putElement(new Position(6,6), robot);
		board7.putElement(new Position(6,6), battery2);
		board7.putElement(new Position(6,6), battery1);
		robot.pickUp(battery2);
		robot.pickUp(battery1);
		robot.terminate();
		assertTrue(robot.isTerminated());
		assertTrue(battery1.isTerminated());
		assertTrue(battery2.isTerminated());
		assertNull(robot.getBoard());
		assertNull(battery1.getBoard());
		assertNull(battery2.getBoard());
		board7.terminate();
	}
	
	//use tests
	
	@Test
	public final void use_Legal_TotalAmountTransfer(){
		Board board7 = new Board(7,7);
		facade.addBoard(board7);
		
		Robot robot = new Robot(Orientation.DOWN,thousandEnergy.multiplyAndReturn(0.1));
		Battery battery = new Battery(thousandEnergy.multiplyAndReturn(0.1),500);
		board7.putElement(new Position(3,3), robot);
		board7.putElement(new Position(3,3), battery);
		robot.pickUp(battery);
		robot.use(battery);
		assertEquals(thousandEnergy.multiplyAndReturn(0.2), robot.getEnergy());
		assertEquals(zeroEnergy, battery.getEnergy());
		assertTrue(battery.isTerminated());
		board7.terminate();
	}
	
	@Test
	public final void use_Legal_PartAmountTransfer(){
		Board board7 = new Board(7,7);
		facade.addBoard(board7);
		
		Robot robot = new Robot(Orientation.DOWN,new EnergyAmount(14950,EnergyUnit.WATTSECONDS));
		Battery battery = new Battery(thousandEnergy.multiplyAndReturn(0.1),500);
		board7.putElement(new Position(3,3), robot);
		board7.putElement(new Position(3,3), battery);
		robot.pickUp(battery);
		robot.use(battery);
		assertEquals(robot.getMaxEnergy(), robot.getEnergy());
		assertEquals(robot.getMaxEnergy().subtractAndReturn(new EnergyAmount(14950,EnergyUnit.WATTSECONDS)), battery.getEnergy());
		assertTrue(battery.isTerminated());
		board7.terminate();
	}
	
	@Test
	public final void use_Illegal(){
		Board board7 = new Board(7,7);
		facade.addBoard(board7);
		
		Robot robot = new Robot(Orientation.DOWN,thousandEnergy.multiplyAndReturn(0.1));
		Battery battery = new Battery(thousandEnergy.multiplyAndReturn(0.2),500);
		board7.putElement(new Position(3,3), robot);
		board7.putElement(new Position(3,3), battery);
		try{
			robot.use(battery);
		}
		catch(IllegalStateException e){
			assertEquals(thousandEnergy.multiplyAndReturn(0.1), robot.getEnergy());
			assertEquals(thousandEnergy.multiplyAndReturn(0.2), battery.getEnergy());
			assertFalse(battery.isTerminated());
		}
		board7.terminate();
	}
	
	//drop tests
	
	@Test
	public final void drop_Legal_2ItemsInPossession(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(10));
		Battery battery1  = new Battery(thousandEnergy, 200);
		Battery battery2 = new Battery(thousandEnergy,500);
		board9.putElement(new Position(0,0), robot);
		board9.putElement(new Position(0,0), battery1);
		board9.putElement(new Position(0,0), battery2);
		robot.pickUp(battery1);
		robot.pickUp(battery2);
		robot.move();
		robot.drop(battery1);
		assertEquals(500, robot.getLoad());
		assertEquals(1, robot.getNbOfItems());
		assertEquals(robot.getBoard(), battery1.getBoard());
		assertEquals(new Position(1,0), battery1.getPosition());
		board9.terminate();
	}
	
	@Test
	public final void drop_Legal_1ItemInPossession(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(10));
		Battery battery1  = new Battery(thousandEnergy, 200);
		board9.putElement(new Position(3,5), robot);
		board9.putElement(new Position(3,5), battery1);
		robot.pickUp(battery1);
		robot.move();
		robot.drop(battery1);
		assertEquals(0, robot.getNbOfItems());
		assertEquals(robot.getBoard(), battery1.getBoard());
		assertEquals(new Position(4,5), battery1.getPosition());
		board9.terminate();
	}
	
	@Test
	public final void drop_Illegal_ItemNotInPossession(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(10));
		Battery battery1  = new Battery(thousandEnergy, 200);
		board9.putElement(new Position(3,5), robot);
		board9.putElement(new Position(3,5), battery1);
		try{
			robot.drop(battery1);
			assertTrue(false);
		}
		catch (IllegalStateException e) {
			assertTrue(true);
		}
		assertEquals(0, robot.getNbOfItems());
		assertEquals(robot.getBoard(), battery1.getBoard());
		assertEquals(new Position(3,5), battery1.getPosition());
		board9.terminate();
	}
	
	@Test
	public final void drop_Illegal_Terminated(){
		Board board9 = new Board(9,9);
		facade.addBoard(board9);
		
		Robot robot = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(10));
		Battery battery1  = new Battery(thousandEnergy, 200);
		board9.putElement(new Position(3,5), robot);
		board9.putElement(new Position(3,5), battery1);
		robot.pickUp(battery1);
		robot.move();
		robot.terminate();
		try{
			robot.drop(battery1);
			assertTrue(false);
		}
		catch (IllegalTerminatedException e) {
			assertTrue(true);
		}
		assertTrue(battery1.isTerminated());
		board9.terminate();
	}
	
	@Test
	public final void execute(){
		Board board9test1 = new Board(9,9);
		facade.addBoard(board9test1);
		Robot robot1500 = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(1.5));
		board9test1.putElement(new Position(1, 1), robot1500);
		robot1500.saveProg("(if(energy-at-least 1100) (seq(move)(turn clockwise))(turn counterclockwise))");
		robot1500.executeMyProg();
		assertEquals(thousandEnergy.multiplyAndReturn(0.9), robot1500.getEnergy());
		assertEquals(Orientation.DOWN, robot1500.getOrientation());
		assertEquals(new Position(2,1), robot1500.getPosition());
		board9test1.terminate();
	}
	
	@Test
	public final void executeSingleStep(){
		Board board9test = new Board(9,9);
		facade.addBoard(board9test);
		Robot robottest = new Robot(Orientation.RIGHT,thousandEnergy.multiplyAndReturn(1.5));
		board9test.putElement(new Position(1, 1), robottest);
		robottest.saveProg("(if(energy-at-least 1100) (seq(move)(turn clockwise))(turn counterclockwise))");
		robottest.executeSingleStepOfProg();
		assertEquals(thousandEnergy, robottest.getEnergy());
		assertEquals(Orientation.RIGHT, robottest.getOrientation());
		assertEquals(new Position(2,1), robottest.getPosition());
		robottest.executeSingleStepOfProg();
		assertEquals(thousandEnergy.multiplyAndReturn(0.9), robottest.getEnergy());
		assertEquals(Orientation.DOWN, robottest.getOrientation());
		assertEquals(new Position(2,1), robottest.getPosition());
		robottest.executeSingleStepOfProg();
		assertEquals(thousandEnergy.multiplyAndReturn(0.8), robottest.getEnergy());
		assertEquals(Orientation.RIGHT, robottest.getOrientation());
		assertEquals(new Position(2,1), robottest.getPosition());
		board9test.terminate();
	}
	
	@Test
	public final void teleport(){
		Board board = new Board(9,9);
		facade.addBoard(board);
		Robot robot = new Robot();
		board.putElement(new Position(4,5), robot);
		robot.teleport();
		assertNotSame(new Position(4,5), robot.getPosition());
		assertEquals(new EnergyAmount(15000,EnergyUnit.WATTSECONDS), robot.getEnergy());
		board.terminate();
	}
	
	@Test
	public final void transferItems_IllegalCase(){
		Board board = new Board(9,9);
		facade.addBoard(board);
		Robot robot1 = new Robot();
		Robot robot2 = new Robot();
		board.putElement(new Position(4,5), robot1);
		board.putElement(new Position(1,2), robot2);
		Battery battery = new Battery();
		RepairKit rep = new RepairKit();
		RepairKit rep2 = new RepairKit();
		robot1.addItem(battery);
		robot1.addItem(rep);
		robot2.addItem(rep2);
		try{
			robot1.transferItems(robot2);
			assertTrue(false);
		}
		catch(IllegalStateException e){
			assertTrue(true);
		}
		assertEquals(2, robot1.getNbOfItems());
		assertEquals(1, robot2.getNbOfItems());
		board.terminate();
	}
	
	@Test
	public final void transferItems_Terminated(){
		Board board = new Board(9,9);
		facade.addBoard(board);
		Robot robot1 = new Robot();
		Robot robot2 = new Robot();
		board.putElement(new Position(4,5), robot1);
		board.putElement(new Position(4,6), robot2);
		Battery battery = new Battery();
		RepairKit rep = new RepairKit();
		RepairKit rep2 = new RepairKit();
		robot1.addItem(battery);
		robot1.addItem(rep);
		robot2.addItem(rep2);
		robot1.terminate();
		try{
			robot1.transferItems(robot2);
			assertTrue(false);
		}
		catch(IllegalTerminatedException e){
			assertTrue(true);
		}
		assertEquals(1, robot2.getNbOfItems());
		board.terminate();
	}
	
	@Test
	public final void transferItems_LegalCase(){
		Board board = new Board(9,9);
		facade.addBoard(board);
		Robot robot1 = new Robot();
		Robot robot2 = new Robot();
		board.putElement(new Position(4,5), robot1);
		board.putElement(new Position(4,6), robot2);
		Battery battery = new Battery();
		RepairKit rep = new RepairKit();
		RepairKit rep2 = new RepairKit();
		robot1.addItem(battery);
		robot1.addItem(rep);
		robot2.addItem(rep2);
		try{
			robot1.transferItems(robot2);
			assertTrue(true);
		}
		catch(IllegalStateException e){
			assertTrue(false);
		}
		assertEquals(0, robot1.getNbOfItems());
		assertEquals(3, robot2.getNbOfItems());
		assertTrue(robot2.getItems().contains(rep));
		assertTrue(robot2.getItems().contains(rep2));
		assertTrue(robot2.getItems().contains(battery));
		board.terminate();
	}
	
	@Test
	public final void hit(){
		EnergyAmount maxBefore = robotOrient0Energy15000.getMaxEnergy();
		robotOrient0Energy15000.hit();
		assertEquals(maxBefore.subtractAndReturn(new EnergyAmount(4,EnergyUnit.KILOJOULE)), robotOrient0Energy15000.getMaxEnergy());
	}
	@Test
	public final void hit_terminated(){
		EnergyAmount maxBefore = robotOrient0Energy15000.getMaxEnergy();
		robotOrient0Energy15000.terminate();
		try{
			robotOrient0Energy15000.hit();
			assertTrue(false);
		}
		catch (IllegalTerminatedException e) {
			assertTrue(true);		
			}
		assertEquals(maxBefore, robotOrient0Energy15000.getMaxEnergy());
	}
	
	@Test
	public final void saveProg_LegalCase(){
		try{
			robotOrient0Energy15000.saveProg("(if(not(wall))(turn clockwise)(move))");
			assertTrue(true);
		}
		catch (IllegalArgumentException e) {
			assertTrue(false);
		}
		assertNotSame(null, robotOrient0Energy15000.getSavedProgram());
	}
	
	@Test
	public final void saveProg_IllegalCase(){
		try{
			robotOrient0Energy15000.saveProg("(if(not(wall))(turn clockwise))");
			assertTrue(false);
		}
		catch (IllegalArgumentException e) {
			assertTrue(true);
		}
		assertSame(null, robotOrient0Energy15000.getSavedProgram());
	}
	
	@Test
	public final void toStringTest(){
		Robot robot = new Robot(Orientation.UP,new EnergyAmount(4,EnergyUnit.KILOJOULE));
		robot.addItem(new Battery(new EnergyAmount(4,EnergyUnit.KILOJOULE), 1050));
		assertEquals("ROBOT with energy 4.0 kJ, carrying 1 items (1050 g)", robot.toString());
	}
	
	
	
}
